#include "protocol.h"

CmdData cmd_save;

static protocolComType_t pUartHandle;

__attribute__((weak)) void protocol_callback(CmdData cmd);
__attribute__((weak)) void protocol_data_write(uint8_t data);

static uint8_t CheckSumCal(uint8_t *pData, uint32_t num) {
    if (pData == NULL) {
        return 0x00;
    }
    if (num == 0) {
        return 0x00;
    }
    uint8_t crc_data = 0x00;

    for (uint32_t i = 0; i < num; i++) {
        /*仅保留低位*/
        crc_data += 0xff & pData[i];
    }
    return crc_data;
}

static void InitPtcStruct() {
    pUartHandle.step        = 0;
    pUartHandle.tmpCnt      = 0;
    pUartHandle.aRxBufIndex = 0;
    pUartHandle.aRxCrcIndex = 0;
}

void protocol_rec_put(uint8_t data) {
    switch (pUartHandle.step) {
        case 0:
            if (data == FRAME_HEAD_SAME_FA) { /*帧头正确*/
                pUartHandle.step++;           /*跳转下一步骤*/
                pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = data;
            }
            break;
        case 1:
            if (data == FRAME_HEAD_SAME_FA) {
                pUartHandle.step =
                    1; /*第一帧头重复，回到第二帧头判断处,AA 55 AA 55的情况*/
                pUartHandle.aRxBufIndex = 1; /*更新第二帧头*/
            } else {
                pUartHandle.tmpCnt = data + 1; /*临时计数值*/
                pUartHandle.step++;            /*跳转下一步骤*/
                pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] =
                    data; /*压入缓冲区*/
                if (((RX_BUF_LENGTH - pUartHandle.aRxBufIndex) < data) ||
                    (data == 0)) { /*缓冲区溢出或数据长度为 0*/
                    InitPtcStruct(); /*初始化结构体值,准备下一次接收*/
                }
            }
            break;
        case 2:
            if ((--pUartHandle.tmpCnt) > 0) { /*接收数据到缓冲区*/
                pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = data;
                if (pUartHandle.aRxBufIndex >=
                    RX_BUF_LENGTH) { /*长度被意外修改，导致缓冲区溢出*/
                    InitPtcStruct(); /*初始化结构体值,准备下一次接收*/
                }
            } else {
                if (pUartHandle.aRxBufIndex > 7 &&
                    CheckSumCal(&pUartHandle.aRxBuf[0],
                                pUartHandle.aRxBufIndex + 1) == data) {
                    cmd_save.src                = pUartHandle.aRxBuf[2];
                    cmd_save.dst                = pUartHandle.aRxBuf[3];
                    cmd_save.seq                = pUartHandle.aRxBuf[4];
                    cmd_save.res                = pUartHandle.aRxBuf[5];
                    cmd_save.payload.cmd_id     = pUartHandle.aRxBuf[6];
                    cmd_save.payload.ack_flag   = pUartHandle.aRxBuf[7];
                    cmd_save.payload.cmd_length = pUartHandle.aRxBufIndex - 8;
                    cmd_save.payload.cmd_value  = (uint8_t *)malloc(
                        sizeof(uint8_t) * cmd_save.payload.cmd_length);
                    for (int i = 0; i < cmd_save.payload.cmd_length; i++) {
                        cmd_save.payload.cmd_value[i] =
                            pUartHandle.aRxBuf[8 + i];
                    }
                    protocol_callback(cmd_save);
                    free(cmd_save.payload.cmd_value);
                }
                InitPtcStruct(); /*初始化结构体值,准备下一次接收*/
            }
            break;

        default:
            InitPtcStruct(); /*初始化结构体值,准备下一次接收*/
            break;
    }
}

void protocol_send_data(CmdData data) {
    protocolComType_t pUartHandle;
    pUartHandle.aRxBufIndex                       = 0;
    pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = FRAME_HEAD_SAME_FA;

    pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = data.payload.cmd_length + 6;
    uint8_t *ptx                                  = (uint8_t *)&data;
    for (int i = 0; i < 6; i++) {
        pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = ptx[i];
    }

    if (data.payload.cmd_length) {
        ptx = data.payload.cmd_value;
        for (int i = 0; i < data.payload.cmd_length; i++) {
            pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = ptx[i];
        }
    }

    uint8_t check =
        CheckSumCal(&pUartHandle.aRxBuf[0], 8 + data.payload.cmd_length);
    pUartHandle.aRxBuf[pUartHandle.aRxBufIndex++] = check;

    for (int i = 0; i < pUartHandle.aRxBufIndex; i++) {
        protocol_data_write(pUartHandle.aRxBuf[i]);
    }
    InitPtcStruct();
}